package com.gossip.manager;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.File;
import java.util.ArrayList;
import java.util.Date;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.*;


import com.gossip.*;

public class MemberManager {
	private static int maxFailedCount = 5;
	
	public MemberManager(){}
	
	public ArrayList<GossipMember> ReadRemoteMemberList()
	  throws IOException
	{
		 ArrayList<GossipMember> members = new ArrayList<GossipMember>(); 
		 File memberFile=new File("member.txt");
		 GossipService.debug("Get remote member from member file" + memberFile.getAbsolutePath());
         if(!memberFile.exists()||memberFile.isDirectory())
             throw new FileNotFoundException();
         BufferedReader br=new BufferedReader(new FileReader(memberFile));
         String temp=null;
         temp=br.readLine();
         while(temp!=null&&temp.trim()!=""&&temp.length()>0){
        	 GossipMember remotemember = ConvertGossipMember(temp);
        	 if(temp!=null)
        		 members.add(remotemember);
             temp=br.readLine();
         }
         return members;
	}
	
	protected RemoteGossipMember ConvertGossipMember(String jsonStr)
	{
		if(jsonStr==null) 
			return null;
		if(jsonStr.trim()=="") 
			return null;
		JSONObject jsonObject = null;
		RemoteGossipMember member = null;
		try {
			jsonObject = new JSONObject(jsonStr);
			int port = Integer.parseInt(jsonObject.getString("port"));
			int memberId = Integer.parseInt(jsonObject.getString("memberId"));
			Date heartbeat = new Date(jsonObject.getLong("heartbeat"));
			member = new RemoteGossipMember(jsonObject.getString("name"),jsonObject.getString("host"), port, heartbeat, memberId);
			member.setFailedCount(jsonObject.getInt("failedCount"));
		} catch (JSONException e) {
			e.printStackTrace();
			return null;
		}
		return member;
	}
	
	public static void MergeList(GossipMember me,ArrayList<GossipMember> srcMems, ArrayList<GossipMember> desMems)
	{
	    boolean found = false;
	    boolean changed = false;
		for(GossipMember member: desMems)
		{
			found = false;
			for(int i = srcMems.size()-1;i>=0;i--)
			{
				GossipMember memSrc = srcMems.get(i);
				if(member.getMemberId()== memSrc.getMemberId())
				{
					found = true;
					if(member.getHeartbeat().after(memSrc.getHeartbeat()))
					{
						memSrc.setHeartbeat(member.getHeartbeat());
						int failedCount = ((RemoteGossipMember)member).getFailedCount();
						((RemoteGossipMember)memSrc).setFailedCount(failedCount);
					    changed = true;
					    break;
					}
				}
			}
			if(!found&&member.getMemberId()!=me.getMemberId())
			{
				srcMems.add(member);
				changed = true;
			}
		}
		if(changed)
		{
			try {
				setListGroup(srcMems);
				SaveMemberList(srcMems);
			} catch (IOException e) {
				GossipService.error("catch save members");
				e.printStackTrace();
			}
		}
	}
	
	private static void setListGroup(ArrayList<GossipMember> srcMems)
	{
		int[] intIds = new int[srcMems.size()]; 
		for(int i = 0 ; i<srcMems.size();i++)
		{
			intIds[i] = srcMems.get(i).getMemberId();
		}
		Arrays.sort(intIds);
		String s = ""; 
		for(int i = 0 ; i<srcMems.size();i++)
		{
			s = s + intIds[i]+"  ";
		}
		GossipService.error("sort: " + s);
		int maxGroupNum = 2;
		int groupId = 0;
		int temNumber = 1;
		GossipMember member = null;
		for(int i=0;i<intIds.length;i++)
		{
			member = null;
			int tempId = intIds[i];
			for(int j=0;j<srcMems.size();j++)
			{
				if(tempId == srcMems.get(j).getMemberId())
				{
					member = srcMems.get(j);
					break;
				}
			}
			if(member == null)
			{
				GossipService.error("Error null member in setListGroup");
				continue;
			}
			GossipService.debug("M_id:" + member.getMemberId());
			if(member instanceof RemoteGossipMember)
			{
				if(((RemoteGossipMember)member).getFailedCount()>=maxFailedCount)
					member.setGroupId(-1);
				else
				{
					member.setGroupId(groupId);
					if(temNumber>=maxGroupNum)
					{
						temNumber = 1;
						groupId++;
					}
					else
						temNumber++;
				}
			}
			else
			{
				member.setGroupId(groupId);
				if(temNumber>=maxGroupNum)
				{
					temNumber = 1;
					groupId++;
				}
				else
					temNumber++;
			}
		}
	}

	public static void  SaveMemberList(ArrayList<GossipMember> members) throws IOException
	{
		GossipService.debug("SaveMemberList called"); 
		FileOutputStream erasor = new FileOutputStream("member.txt");
		String str = new String();
		erasor.write(str.getBytes());
		erasor.flush();
		erasor.close();
		erasor = new FileOutputStream("member.txt");
		for(GossipMember member: members)
		{
			JSONObject obj = member.toJSONObjectWithGroupId();
			if(obj!=null)
			{
				GossipService.debug("write member file: "+obj.toString()); 
				erasor.write((obj.toString()+"\r\n").getBytes());
			}
		}
		erasor.flush();
		erasor.close();
	}

}
